<?php

namespace yphp;

use think\Exception;

/**
 * Class Model
 * @package yphp
 * 数据库模型
 */
class Model extends DbBase
{
    //+----------------------------------------------------------------------
    //  随机主从数据库地址
    //+----------------------------------------------------------------------

    // 读数据库地址关联数组
    private static $sl;

    // 获取读数据地址库组
    final protected static function reads()
    {
        if (is_null(self::$sl)) {
            $slave = Config::database('model.slave') ;
            if (!$slave) throw new \Exception('未填写从数据库信息');
            self::$sl = $slave;
        } else {
            $slave = self::$sl;
        }
        return $slave;
    }

    // 写数据库地址
    private static $master;

    // 获取写数据库地址
    final protected static function master()
    {
        return is_null(self::$master) ? self::$master = Config::database('model.master') : self::$master;
    }

    // 读数据库地址
    private static $slave;

    // 获取读数据库地址
    final protected static function slave()
    {
        return is_null(self::$slave) ? self::$slave = Random::instance(self::reads())->getNode() : self::$slave;
    }

    //+----------------------------------------------------------------------
    //  库、表、字段信息
    //+----------------------------------------------------------------------

    // 库表名数组
    protected static $names = [];

    // 初始化库表名
    final protected static function names()
    {
        $class = get_called_class();
        if (!key_exists($class, self::$names)) {
            if(!strpos($class, 'app\\model\\') === 0) throw new \Exception('数据库模型' . $class . '异常');
            if(!($name = substr($class, 10))) throw new \Exception('数据库模型' . $class . '异常');
            $arr = array_reverse(explode('\\', $name));
            self::$names[$class] = ['dbn' => key_exists(1, $arr) ? strtolower($arr[1]) : Config::databaseSpot('link', self::slave())['dbn'], 'tbn' => $class::$dth . strtolower($arr[0])];
        }
        return self::$names[$class];
    }

    // 获取库名
    final protected static function dbn()
    {
        return self::names()['dbn'];
    }

    // 获取表名
    final protected static function tbn()
    {
        return self::names()['tbn'];
    }

    // 表前缀
    protected static $dth = '';

    // 获取表结构
    final protected static function desc()
    {
        return self::describe(self::slave(), self::dbn(), self::tbn());
    }

    // 主键及对象锁定
    final protected static function primaryKey($id)
    {
        $desc = self::desc();
        $primaryKey = $desc->primaryKey;
        if(is_null($primaryKey)){
            throw new \Exception('库 ' . self::dbn() . ' 中表 ' . self::tbn() . ' 主键不存在');
        }
        return [$primaryKey, self::parseValue($desc->list->$primaryKey, $id)];
    }

    //+----------------------------------------------------------------------
    //  表SQL封装
    //+----------------------------------------------------------------------

    // 查询
    final static function query($sql, $bind = [], $rArr = false)
    {
        return self::inQuery(self::setDbn(self::slave(), self::dbn()), $sql, $bind, $rArr);
    }

    // 修改
    final static function execute($sql, $bind = [], $insert = false)
    {
        return self::modify(self::setDbn(self::master(), self::dbn()), $sql, $bind, $insert);
    }

    //+----------------------------------------------------------------------
    //  表操作(类)
    //+----------------------------------------------------------------------

    // 重置表结构
    final static function truncate()
    {
        $tbn = self::tbn();
        return self::execute(" TRUNCATE TABLE `$tbn` ");
    }

    // 查询全部行
    final static function all($field = '*', $rArr = false)
    {
        $fields = is_array($field) ? '`' . implode('`,`', $field) . '`' : $field;
        $tbn = self::tbn(self::slave());
        return self::query(" SELECT $fields FROM `$tbn` ", [], $rArr);
    }

    // 删除指定行
    final static function destroy($id)
    {
        list($primaryKey, $id) = self::primaryKey($id);
        $tbn = self::tbn(self::master());
        return self::execute(" DELETE FROM `$tbn` WHERE `$primaryKey` = :id ", [':id' => $id]);
    }


    //+----------------------------------------------------------------------
    //  静态指定对象
    //+----------------------------------------------------------------------

    // 条件
    final static function which($where, $bind = null, $obj = null)
    {
        return is_null($obj) ? static::instance()->whereBind($where, $bind) : $obj->whereBind($where, $bind);
    }

    // 主键
    final static function assign($id, $obj = null)
    {
        list($primaryKey, $id) = self::primaryKey($id);
        return self::which("$primaryKey = :id", [':id' => $id], $obj);
    }

    //+----------------------------------------------------------------------
    //  单例对象
    //+----------------------------------------------------------------------

    # 对象属性集合
    function construct()
    {
        $this->componet(self::tbn(), Config::database('model.dth'));
        return false;
    }

    //+----------------------------------------------------------------------
    //  表操作(对象)
    //+----------------------------------------------------------------------

    // 增
    final function insert()
    {
        list($sql, $bind) = $this->insertSql(self::master(), self::dbn());
        return self::execute($sql, $bind, true);
    }

    // 删
    final function delete()
    {
        list($sql, $bind) = $this->deleteSql();
        return self::execute($sql, $bind);
    }

    // 改
    final function update()
    {
        list($sql, $bind) = $this->updateSql();
        return self::execute($sql, $bind);
    }

    // 查多行
    final function select($rArr = false)
    {
        list($sql, $bind) = $this->selectSql();
        return self::query($sql, $bind, $rArr);
    }


}